package elitech.vietnam.copyweatherfashion;

import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

import org.xmlpull.v1.XmlPullParserException;

import android.content.Context;
import android.content.Intent;
import android.content.IntentSender;
import android.content.SharedPreferences;
import android.content.pm.PackageInfo;
import android.location.Location;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.provider.Settings;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AnimationUtils;
import android.widget.Toast;

import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesClient;
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.gcm.GoogleCloudMessaging;
import com.google.android.gms.location.LocationClient;
import com.google.gson.Gson;

import elitech.vietnam.copyweatherfashion.config.Const;
import elitech.vietnam.copyweatherfashion.config.Options;
import elitech.vietnam.copyweatherfashion.dialog.ConfirmDialogFragment;
import elitech.vietnam.copyweatherfashion.dialog.ConfirmDialogFragment.ConfirmDialogClick;
import elitech.vietnam.copyweatherfashion.dialog.ConfirmDialogFragment.Type;
import elitech.vietnam.copyweatherfashion.entities.Member;
import elitech.vietnam.copyweatherfashion.location.GeoObject;
import elitech.vietnam.copyweatherfashion.location.Geocoding;
import elitech.vietnam.copyweatherfashion.location.MyLocation;
import elitech.vietnam.copyweatherfashion.prefs.PrefsDefinition;
import elitech.vietnam.copyweatherfashion.utilities.ServerClock;
import elitech.vietnam.copyweatherfashion.utilities.Tracker;
import elitech.vietnam.copyweatherfashion.utilities.Utilities;
import elitech.vietnam.copyweatherfashion.weather.WeatherService;
import elitech.vietnam.copyweatherfashion.weather.objects.WeatherObject;
import elitech.vietnam.copyweatherfashion.wsclient.Service;

public class SplashActivity extends FragmentActivity {

	private static final int	TASKS								= 4;

	public final static int		PLAY_SERVICES_RESOLUTION_REQUEST	= 9000;
	public final static String	UNIQUE_DEVICE_ID					= "UNIQUE_DEVICE_ID";
	public static final String	EXTRA_MESSAGE						= "message";
	private final static String	SENDER_ID							= "793977106476";

	SharedPreferences			mPrefs;
	Options						mOptions;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_splash_screen);

		mPrefs = getSharedPreferences(getPackageName(), MODE_PRIVATE);
		/**
		 * Initialize options
		 */
		mOptions = new Gson().fromJson(mPrefs.getString(PrefsDefinition.OPTION, ""), Options.class);
		if (mOptions == null) {
			mOptions = new Options();
			mPrefs.edit().putString(PrefsDefinition.OPTION, new Gson().toJson(mOptions)).commit();
		}

		if (savedInstanceState == null) {
			getSupportFragmentManager().beginTransaction().add(R.id.container, new PlaceholderFragment()).commit();
		}
	}

	@Override
	public void onBackPressed() {
		super.onBackPressed();
	}

	/**
	 * A placeholder fragment containing a simple view.
	 */
	public static class PlaceholderFragment extends Fragment implements ConfirmDialogClick,
			GooglePlayServicesClient.ConnectionCallbacks, GooglePlayServicesClient.OnConnectionFailedListener {

		SplashActivity			mActivity;
		GoogleCloudMessaging	gcm		= null;

		Location				mLocation;
		View					mMainView;
		LocationClient			mClient;

		int						mTask	= 0;

		public PlaceholderFragment() {
		}

		@Override
		public void onCreate(Bundle savedInstanceState) {
			super.onCreate(savedInstanceState);
			mActivity = (SplashActivity) getActivity();
		}

		@Override
		public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
			mMainView = inflater.inflate(R.layout.fragment_splash_screen, container, false);
			return mMainView;
		}

		@Override
		public void onResume() {
			super.onResume();

			mMainView.startAnimation(AnimationUtils.loadAnimation(mActivity, R.anim.fade_splashin));
			/*
			 * Checking for network state
			 */
			ConnectivityManager conMgr = (ConnectivityManager) mActivity.getSystemService(Context.CONNECTIVITY_SERVICE);
			NetworkInfo i = conMgr.getActiveNetworkInfo();
			if (i == null) {
				/*
				 * Device does not support network
				 */
			} else if (!i.isAvailable() || !i.isConnected()) {
				/*
				 * Open network setting to enable network
				 */
				new ConfirmDialogFragment.Builder().setMessage(getString(R.string.internet_connection_request))
						.setTargetFragment(this)
						.setType(Type.FRAGMENT)
						.build().show(getFragmentManager());
			} else if (!checkPlayServices()) {
				mActivity.finish();
			} else if (mActivity.mOptions.mLocation) {
				mClient = new LocationClient(mActivity, this, this);
				mClient.connect();
			} else {
				startGetData(Const.DEFAULT_LATITUDE, Const.DEFAULT_LONGTITUDE);
			}
		}

		@Override
		public void onConnectionFailed(ConnectionResult connectionResult) {
			if (connectionResult.hasResolution()) {
				try {
					// Start an Activity that tries to resolve the error
					connectionResult.startResolutionForResult(mActivity, PLAY_SERVICES_RESOLUTION_REQUEST);
					/*
					 * Thrown if Google Play services canceled the original
					 * PendingIntent
					 */
				} catch (IntentSender.SendIntentException e) {
					e.printStackTrace();
				}
			} else {
				Toast.makeText(mActivity, R.string.errorconnectgoogleservices, Toast.LENGTH_SHORT).show();
				mActivity.finish();
			}
		}

		@Override
		public void onConnected(Bundle arg0) {
			startGetData();
		}

		@Override
		public void onDisconnected() {
			Log.w("Location Client", "Location client disconnected. Please re-connect");
		}
		
		private void startGetData(double lat, double lng) {
			mTask = 0;
			new GetServerTime().execute();
			new OneTimeStoreID().execute();
			new GetAddress().execute(lat, lng);
			new GetWeather().execute(lat, lng);
		}

		private void startGetData() {
			final int MAXTIME = 5000;
			new AsyncTask<Integer, Integer, Boolean>() {
				@Override
				protected Boolean doInBackground(Integer... params) {
					int time = 0;
					do {
						try {
							mLocation = mClient.getLastLocation();
							Thread.sleep(200);
						} catch (InterruptedException | IllegalStateException e) {
							e.printStackTrace();
							break;
						}
						time += 200;
					} while (time < MAXTIME && mLocation == null);
					return null;
				}
				@Override
				protected void onPostExecute(Boolean result) {
					Log.w("Get Location", "Location discovered");
					mClient.disconnect();
					double lat = (mLocation == null) ? Const.DEFAULT_LATITUDE : mLocation.getLatitude();
					double lng = (mLocation == null) ? Const.DEFAULT_LONGTITUDE : mLocation.getLongitude();
					mTask = 0;
					new GetServerTime().execute();
					new OneTimeStoreID().execute();
					new GetAddress().execute(lat, lng);
					new GetWeather().execute(lat, lng);
				}
			}.execute();
		}

		@Override
		public void yesClick() {
			Intent intent = new Intent(Settings.ACTION_WIRELESS_SETTINGS);
			startActivity(intent);
		}

		@Override
		public void noClick() {
			mActivity.finish();
		}

		void finishTask() {
			mTask += 1;
			Log.w("Tasks", mTask + "");
			if (mTask == TASKS) {
				Intent intent = new Intent(mActivity, MainActivity.class);
				mActivity.startActivity(intent);
				mActivity.finish();
			}
		}

		private boolean checkPlayServices() {
			int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(mActivity);
			if (resultCode != ConnectionResult.SUCCESS) {
				if (GooglePlayServicesUtil.isUserRecoverableError(resultCode)) {
					GooglePlayServicesUtil.getErrorDialog(resultCode, mActivity, PLAY_SERVICES_RESOLUTION_REQUEST)
							.show();
				} else {
					Log.w("GCM", "This device is not supported.");
					Toast.makeText(mActivity, R.string.devicenotsupportgoogleservices, Toast.LENGTH_LONG)
							.show();
					mActivity.finish();
				}
				return false;
			}
			return true;
		}

		class GetWeather extends AsyncTask<Double, Integer, WeatherObject> {
			@Override
			protected WeatherObject doInBackground(Double... params) {
				try {
					Log.w("Get Weather", "Begin get weather...");
					return new WeatherService().getWeatherByCoor(params[0], params[1]);
				} catch (IOException e) {
					e.printStackTrace();
				}
				return null;
			}

			@Override
			protected void onPostExecute(WeatherObject result) {
				if (result == null) {
					Toast.makeText(mActivity, R.string.cannotgetweather, Toast.LENGTH_SHORT).show();
					mActivity.finish();
				} else {
					mActivity.mPrefs.edit().putString(PrefsDefinition.WEATHER, new Gson().toJson(result)).commit();
					finishTask();
				}
			}
		}

		class GetAddress extends AsyncTask<Double, Integer, Boolean> {
			double	lat, lon;

			@Override
			protected Boolean doInBackground(Double... params) {
				lat = params[0];
				lon = params[1];
				Locale locale = getResources().getConfiguration().locale;
				Log.w("Get Address", "Begin get address...");
				String data = "";
				try {
					data = Geocoding.reverseGeocoder(params[0], params[1], locale);
				} catch (IOException e) {
					e.printStackTrace();
				}
				if (data.length() != 0) {
					data = new Gson().toJson(new MyLocation(params[0], params[1], new Gson().fromJson(data,
							GeoObject.class)));
					mActivity.mPrefs.edit().putString(PrefsDefinition.LOCATION, data).commit();
					return true;
				}
				return false;
			}

			@Override
			protected void onPostExecute(Boolean result) {
				if (!result) {
					mActivity.mPrefs
							.edit()
							.putString(
									PrefsDefinition.LOCATION,
									new Gson().toJson(new MyLocation(lat, lon, new Gson().fromJson(
											Const.DEBUG_KRLOCATION, GeoObject.class)))).commit();
				}
				finishTask();
			}
		}
		
		class GetServerTime extends AsyncTask<Integer, Integer, Boolean> {
			@Override
			protected Boolean doInBackground(Integer... params) {
				try {
					long time1 = System.currentTimeMillis();
					String response = new Service().getCurrentTime();
					long time2 = System.currentTimeMillis();
					Date date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.KOREA).parse(response);
					ServerClock clock = new ServerClock(date.getTime() + time2 - time1, time2);
					mActivity.mPrefs.edit().putString(PrefsDefinition.TIMESYNC, new Gson().toJson(clock)).commit();
					Log.w("GetServerTime", clock.initDate.toString());
				} catch (IOException | XmlPullParserException | ParseException e) {
					e.printStackTrace();
					return false;
				}
				return true;
			}
			@Override
			protected void onPostExecute(Boolean result) {
				if (!result) {
					Toast.makeText(mActivity, "App init failed. Please try again", Toast.LENGTH_LONG).show();
					mActivity.finish();
				} else
					finishTask();
			}
		}

		/**
		 * Get Device ID and Google Cloud Message ID. If failed, app will exit
		 */
		class OneTimeStoreID extends AsyncTask<Integer, Integer, Boolean> {
			String	deviceId	= null;
			String	gcmId		= "";

			@Override
			protected Boolean doInBackground(Integer... params) {
				Log.w("Store Device", "Begin store device id...");
				deviceId = mActivity.mPrefs.getString(UNIQUE_DEVICE_ID, null);
				if (deviceId == null || deviceId.equals("")) {
					deviceId = Tracker.getDeviceID(mActivity.getApplicationContext());
					mActivity.mPrefs.edit().putString(UNIQUE_DEVICE_ID, deviceId).commit();
				}

				gcmId = Utilities.getRegistrationId(mActivity.getApplicationContext());
				if (gcmId.equals("")) {
					try {
						Log.w("GCM", "Registering new GCM-ID");
						if (gcm == null)
							gcm = GoogleCloudMessaging.getInstance(mActivity.getApplicationContext());
						gcmId = gcm.register(SENDER_ID);
						Log.w("GCM", "New GCM-ID" + gcmId);
						Utilities.storeRegistrationId(mActivity.getApplicationContext(), gcmId);
						int res = new Service().newDeviceId(deviceId, gcmId);
						return (res > 0);
					} catch (IOException ex) {
						ex.printStackTrace();
						return false;
					} catch (XmlPullParserException e) {
						e.printStackTrace();
						return false;
					}
				}
				return true;
			}

			@Override
			protected void onPostExecute(Boolean result) {
				if (!result) {
					Log.e("Initialize", "Initialize failed! Now exitting.");
					mActivity.finish();
				} else {
					Log.w("Initialize", "Initialize success.");
					new AsyncTask<Integer, Integer, Boolean>() {
						@Override
						protected Boolean doInBackground(Integer... params) {
							int rs = 0;
							try {
								PackageInfo pInfo = mActivity.getPackageManager().getPackageInfo(
										mActivity.getPackageName(), 0);
								int api = Build.VERSION.SDK_INT;
								Member m = new Gson().fromJson(mActivity.mPrefs.getString(PrefsDefinition.USER, ""),
										Member.class);
								String date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault())
										.format(new Date());
								rs = new Service().appOpenTrack(deviceId, pInfo.versionName, api,
										(m != null) ? m.Username : "", date);
							} catch (Exception e) {
							}
							return rs == 1;
						}
					}.execute();
					finishTask();
				}
			}
		}
	}
}
